package cn.dansj.service.Impl;

import cn.dansj.entity.User;
import cn.dansj.repository.UserRepository;
import cn.dansj.service.UserService;
import cn.dansj.common.utils.crypt.Pbkdf2Sha256;
import cn.dansj.common.utils.transfer.GetTime;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.RandomUtils;
import cn.dansj.common.utils.transfer.Verification;
import cn.dansj.enums.GlobalEnv;
import cn.dansj.common.jdbc.JpaUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.persistence.criteria.Predicate;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class UserServiceImpl implements UserService {
    private final UserRepository userRepository;

    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public Page<User> search(Integer pageNum,
                             Integer pageLimit,
                             String username,
                             String status,
                             String mail,
                             String role) {

        Specification<User> userFind = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> paramsList = new ArrayList<>();
            if (Verification.checkNotNull(mail)) {
                paramsList.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("mail")), Transformation.sqlLikeToLowCase(mail)));
            }
            if (Verification.checkNotNull(username)) {
                paramsList.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("username")), Transformation.sqlLikeToLowCase(username)));
            }
            if (Verification.checkNotNull(role)) {
                paramsList.add(criteriaBuilder.equal(root.get("role"), role));
            }
            if (Verification.checkNotNull(status)) {
                paramsList.add(criteriaBuilder.equal(root.get("status"), status));
            }
            Predicate[] predicates = new Predicate[paramsList.size()];
            return criteriaBuilder.and(paramsList.toArray(predicates));
        };

        Sort sort = Sort.by(Sort.Direction.DESC, "sequence");
        Pageable pageable = PageRequest.of(pageNum - 1, pageLimit, sort);
        return userRepository.findAll(userFind, pageable);
    }

    public void updateUser(User user) {
        Optional.of(userRepository.findById(user.getSequence())
                .orElseGet(() -> userRepository.save(user))).map(entity -> {
            user.setPoint(entity.getPoint());
            user.setPayCount(entity.getPayCount());
            // 使用JpaUtil优雅的写法
            JpaUtil.copyNotNullProperties(user, entity);
            entity.setUpdateTime(GetTime.dbTimestamp());
            return userRepository.save(entity);
        }).orElseGet(() -> userRepository.save(user));
    }

    public User getUser(String identifier) {
        return userRepository.getUser(identifier);
    }

    @Override
    public List<User> getUser() {
        return userRepository.findAll();
    }

    public User getUserBySequence(String sequence) {
        return userRepository.findUserBySequence(sequence);
    }

    @Transactional
    public void updateStatus(String sequence, String status) {
        userRepository.updateStatus(sequence, status, GetTime.dbTimestamp());
    }

    public void save(User user) {
        userRepository.save(user);
    }

    public void save(List<User> users) {
        userRepository.saveAll(users);
    }

    @Override
    public boolean initAdminUser() {
        User adminUser = userRepository.getUser(GlobalEnv.Admin);
        if (adminUser == null) {
            try {
                User user = new User();
                user.setUsername(GlobalEnv.Admin);
                user.setStatus("1");
                user.setSequence(RandomUtils.sequence());
                user.setRole(GlobalEnv.SuperAdmin);
                Timestamp now = new Timestamp(System.currentTimeMillis());
                user.setCrtTime(now);
                user.setUpdateTime(now);
                user.setPassword(Pbkdf2Sha256.encode(GlobalEnv.Admin));
                userRepository.save(user);
                return true;
            } catch (Exception exception) {
                return false;
            }
        }
        return true;
    }

    @Override
    public User getUserByToken(String token) {
        return userRepository.findUserByToken(token);
    }
}
